package org.mifos.boss.webservice.RESTclient;

import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URI;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.mifos.boss.webservice.model.CenterInformationDto;
import org.mifos.boss.webservice.model.ClientInformationDto;
import org.mifos.boss.webservice.model.CollectionSheetDto;
import org.mifos.boss.webservice.model.CustomerHierarchy;
import org.mifos.boss.webservice.model.GroupInformationDto;
import org.mifos.boss.webservice.model.LoanInformationDto;
import org.mifos.boss.webservice.model.PersonnelInformationDto;
import org.mifos.boss.webservice.model.SavingsAccountDetailDto;
import org.mifos.boss.webservice.model.SystemInformationDto;
import org.springframework.http.client.CommonsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;


public class RESTClientController {

	protected static Logger logger = Logger.getLogger(RESTClientController.class);
	protected  String URL = "http://localhost:8080/mifos/";
	
//	private String username;
//	private String password;
	Gson gson;
	RestTemplate restTemplate;
	
	
	public RESTClientController(String username, String password){
		
		restTemplate = prepareRESTTemplate(username, password);
		gson = getGson();
	}
	
	
	public SystemInformationDto callRESTAdminService(){
		String url = URL + "admin/system/id-information.json";
		String result = invokeGetRestService(url);
		
		SystemInformationDto sysDto = gson.fromJson(result, SystemInformationDto.class);
		
		return sysDto;
	}
	
	public CenterInformationDto callRESTCenterService(String globalCustNum){
//		center/num-{globalCustNum}
		String url = URL + "center/num-" + globalCustNum +".json";
		String result = invokeGetRestService(url);
		
		CenterInformationDto centerDto = gson.fromJson(result, CenterInformationDto.class);
		
		return centerDto;
	}
	
	
	public ClientInformationDto callRESTClientService(String globalCustNum){
		//client/num-{globalCustNum}
		
		String url = URL + "client/num-" + globalCustNum +".json";
		String result = invokeGetRestService(url);
		
		ClientInformationDto clientDto = gson.fromJson(result, ClientInformationDto.class);
		
		return clientDto;
		
	}
	
//	/collectionsheet/customer/id-{customerId}
	public CollectionSheetDto callRESTCollectionSheetService(String customerId){
		String url = URL + "collectionsheet/customer/id-" + customerId +".json";
		String result = invokeGetRestService(url);
		
		//get new gson instance with LocalDate conversion adapter
		 gson = (new GsonBuilder()).registerTypeAdapter(LocalDate.class, new LocalDateTypeConverter()).create();
		
		CollectionSheetDto collectionDto = gson.fromJson(result, CollectionSheetDto.class);
		
		System.out.print("Collection sheet DTO  date" + collectionDto.getDate());
		
		return collectionDto;
		
	}
	
	//POST method
	public void callRESTSaveCollectionSheetService() {
//		/collectionsheet/save
		
	}

	public GroupInformationDto callRESTGroupService(String globalCustNum){
//		group/num-{globalCustNum}
		
		String url = URL + "group/num-" + globalCustNum +".json";
		String result = invokeGetRestService(url);
		
		GroupInformationDto groupDto =  gson.fromJson(result, GroupInformationDto.class);
		
		return groupDto;
		
	}
	//post method
	public void callRESTLoanAccountRepayService(){
		
//		/account/loan/repay/num-{globalAccountNum}
		
		
	}
	
	public LoanInformationDto callRESTLoanAccountInfo(String globalAccountNum){
//		/account/loan/num-{globalAccountNum}

		String url = URL + "account/loan/num-" + globalAccountNum +".json";
		String result = invokeGetRestService(url);
		
		LoanInformationDto loanDto =  gson.fromJson(result, LoanInformationDto.class);
		
		return loanDto;
		
	}
	
	public PersonnelInformationDto callRESTCurrentPersonnelService(){
//		personnel/id-current

		String url = URL + "personnel/id-current.json";
		String result = invokeGetRestService(url);
		
		PersonnelInformationDto personnelDto =  gson.fromJson(result, PersonnelInformationDto.class);
		
		return personnelDto;
		
	}
	
	public CustomerHierarchy callRESTCustomerUnderPersonnelService(){
//		personnel/clients/id-current
		
		String url = URL + "personnel/clients/id-current.json";
		String result = invokeGetRestService(url);
		
		CustomerHierarchy customerHierarchy =  gson.fromJson(result, CustomerHierarchy.class);
		
		return customerHierarchy;
		
	}
	
	public SavingsAccountDetailDto callRESTGetSavingAccountService(String globalAccountNum){
//		/account/savings/num-{globalAccountNum}
		String url = URL + "account/savings/num-" + globalAccountNum +".json";
		String result = invokeGetRestService(url);
		
		SavingsAccountDetailDto savingDto =  gson.fromJson(result, SavingsAccountDetailDto.class);
		
		return savingDto;
		
	}
	
	//POST method
	public  void callRESTSavingAccountDepositService(){
		
	}
	
	
	
	public Gson getGson(){

		gson = (new GsonBuilder()).registerTypeAdapter(DateTime.class, new DateTimeTypeConverter()).create();
		return gson;
	}
	
	public String invokeGetRestService(String url){
		
		String result = restTemplate.getForObject(url, String.class);
	
		return result;
	}
	
	public void invokePostRestService(String url, Object request, Class<Object> responseType){
//		restTemplate.postForObject(url, request, responseType)
//		restTemplate.postForObject(url, request, responseType);
	}
	
	public RestTemplate prepareRESTTemplate(String username, String password){
		
		RESTClient rs = new RESTClient(username, password);
		HttpClient httpClient = null;
		try {
			httpClient = rs.prepareConnection();
		} catch (HttpException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		CommonsClientHttpRequestFactory cf = new CommonsClientHttpRequestFactory(httpClient);
		 
		
		return new RestTemplate(cf);
	}

//	public String getPassword() {
//		return password;
//	}
//
//	public void setPassword(String password) {
//		this.password = password;
//	}
//
//	public String getUsername() {
//		return username;
//	}
//
//	public void setUsername(String username) {
//		this.username = username;
//	}
//	
	
}

class DateTimeTypeConverter implements JsonSerializer<DateTime>, JsonDeserializer<DateTime> {
	  // No need for an InstanceCreator since DateTime provides a no-args constructor
	  public JsonElement serialize(DateTime src, Type srcType, JsonSerializationContext context) {
	    return new JsonPrimitive(src.toString());
	  }
	  public DateTime deserialize(JsonElement json, Type type, JsonDeserializationContext context) {
	    try{
		  return new DateTime(json.getAsLong());
	    }catch(IllegalArgumentException e){
	    	
	    }
		return null;
	  }
	}


class LocalDateTypeConverter implements JsonSerializer<LocalDate>, JsonDeserializer<LocalDate> {
	  // No need for an InstanceCreator since DateTime provides a no-args constructor
	  public JsonElement serialize(DateTime src, Type srcType, JsonSerializationContext context) {
	    return new JsonPrimitive(src.toString());
	  }
	  public LocalDate deserialize(JsonElement json, Type type, JsonDeserializationContext context) {
	    try{
	    	if(json.isJsonArray()){
	    		JsonArray dateVal = json.getAsJsonArray();
	    		return new LocalDate(dateVal.get(0).getAsInt(),dateVal.get(1).getAsInt(), dateVal.get(2).getAsInt());
	    		}
	    	}
	    	catch(IllegalArgumentException e){
	    	//is it formatted at [2011,11,11]?
	    	e.printStackTrace();
	    		
	    	}
	    	
	    	return null;
	    } 
	  
	public JsonElement serialize(LocalDate src, Type typeOfSrc,
			JsonSerializationContext context) {
		// TODO Auto-generated method stub
		return null;
	}
}

